package com.ytjj.qmyx.supplychain.service;

import com.google.common.base.Strings;
import com.sun.mail.imap.IMAPStore;
import com.ytjj.qmyx.supplychain.common.exception.ApiException;
import com.ytjj.qmyx.supplychain.common.utils.DateUtil;
import com.ytjj.qmyx.supplychain.common.utils.RedisService;
import com.ytjj.qmyx.supplychain.common.utils.feishu.FeiShuUtil;
import com.ytjj.qmyx.supplychain.mapper.EmailAccountMapper;
import com.ytjj.qmyx.supplychain.mapper.entity.YxEmailAccount;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import javax.mail.search.ComparisonTerm;
import javax.mail.search.SentDateTerm;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author jiawei
 * @date 2024年04月08日 10:01
 * @describe
 */
@Component
@Slf4j
@RefreshScope
public class MailService {
    @Resource
    EmailAccountMapper emailAccountMapper;
    @Resource
    RedisService redisService;
    //报警关键词
    @Value("${emailWarningWords:}")
    private List<String> warningWords;

    /**
     * 邮件服务器
     */
    final static String SMTP_HOST_KEY = "mail.smtp.host";
    final static String SMTP_PORT_KEY = "mail.smtp.port";

    final static String IMAP_HOST_KEY = "mail.imap.host";
    final static String IMAP_PORT_KEY = "mail.imap.port";
    final static String IMAP_AUTH_KEY = "mail.imap.auth";
    final static String IMAP_SSL_KEY = "mail.imap.ssl.enable";
    final static String IMAP_PROTOCOL_KEY = "mail.store.protocol";


    /**
     * 发送邮件
     */
    public void sendMail () {
        // todo 暂未接续开发
        try {
            System.setProperty("mail.mime.splitlongparameters", "false");
            final JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
            javaMailSender.setUsername("账号");
            javaMailSender.setPassword("密码");
            javaMailSender.setHost("smtp.163.com");
            javaMailSender.setPort(25);
            javaMailSender.setProtocol("smtp");
            javaMailSender.setDefaultEncoding("UTF-8");
            Properties mailProperties = new Properties();
            mailProperties.put("mail.smtp.auth", true);
            mailProperties.put("mail.smtp.starttls.enable", true);
            javaMailSender.setJavaMailProperties(mailProperties);
            final MimeMessage mimeMessage = getMimeMessage("接收人", null, null, "这是测试的主题", "邮件正文测试", javaMailSender, null,"发送人");
            javaMailSender.send(mimeMessage);
        } catch (MessagingException e) {
            log.info("发送邮件失败:"+e.getMessage());
        }
    }

    /**
     * 获取收件箱列表
     * @param
     * @return void
     */
    public void receiveMail() {
        Example example = new Example(YxEmailAccount.class);
        example.createCriteria().andEqualTo("isDeleted", 0);
        List<YxEmailAccount> yxEmailAccounts = emailAccountMapper.selectByExample(example);
        for (YxEmailAccount yxEmailAccount : yxEmailAccounts) {
            Folder folder = null;
            Store store = null;
            try {
                if (StringUtils.isEmpty(yxEmailAccount.getPwd())) {
                    throw new ApiException("账号" + yxEmailAccount.getUserName() + "密码为空！");
                }
                // 设置属性
                Properties properties = getProperties(yxEmailAccount.getPlatform(), 2);
                if(null == properties){
                    return;
                }
                Session session = Session.getInstance(properties);
                // 获取Store对象并连接到邮件服务器
                store = session.getStore("imap");
                store.connect(properties.get(IMAP_HOST_KEY).toString(), yxEmailAccount.getUserName(), yxEmailAccount.getPwd());
                Map<String, String> idMap = new HashMap<String, String>();
                //idMap 163官方表示 当您使用IMAP协议接收邮件时候，为了用户帐号信息安全，系统要求您的客户端表明相关“身份”信息才可以允许连接。
                // 这里是一个姓名，可以随便写
                idMap.put("name", "boss");
                idMap.put("version", "7.26");
                idMap.put("os", "windows");
                idMap.put("os-version", "6.1");
                idMap.put("vendor", "boss");// 随便写
                idMap.put("contact", "190362531@qq.com");// 是一个邮箱
                IMAPStore imapStore = (IMAPStore) store;
                imapStore.id(idMap);
                folder = imapStore.getFolder("INBOX");
                folder.open(Folder.READ_ONLY);
                //设置时间查询条件为近3天
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
                calendar.add(Calendar.DAY_OF_MONTH, -2);
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                calendar.set(Calendar.MILLISECOND, 0);
                // ComparisonTerm.GE（大于等于）
                SentDateTerm term = new SentDateTerm(ComparisonTerm.GE, calendar.getTime());
                log.info("邮件查询时间：" + calendar.getTime()+"==>"+DateUtil.dateToStr(calendar.getTime()));
                // 获取收件箱中的当天邮件
                Message[] messages = folder.search(term);
                // 遍历邮件并打印内容
                for (Message msg : messages) {
//                    log.info("邮件主题:" + msg.getSubject());
                    InternetAddress[] address = (InternetAddress[]) msg.getFrom();
                    //这个是发邮件人的地址
                    String from = Optional.ofNullable(address[0].getAddress()).orElse("") ;
                    //这个是发邮件的人的姓名
                    String personal = Optional.ofNullable(address[0].getPersonal()).orElse("");
                    //过滤发件人
                    if (!matchingFrom(from)) {
                        continue;
                    }
                    //邮件作者
                    String fromaddr = personal + "<" + from + ">";
                    log.info(yxEmailAccount.getUserName() + " 获取到当前邮件==================>" + fromaddr);
                    StringBuffer content = new StringBuffer(30);
                    Object mailContent = msg.getContent();
                    if (mailContent instanceof MimeMultipart) {
                        MimeMultipart mimeMultipart = (MimeMultipart) mailContent;
                        for (int j = 0; j < mimeMultipart.getCount(); j++) {
                            BodyPart bodyPart = mimeMultipart.getBodyPart(j);
//                            String disposition = bodyPart.getDisposition();
//                            if (disposition == null || disposition.equals(Part.INLINE)) {
//                                if (bodyPart.isMimeType("text/html") || bodyPart.isMimeType("text/plain")) {
//                                    Object obj = bodyPart.getContent();
//                                    if (obj != null) {
//                                        content.append(obj);
//                                    }else {
//                                        log.info(yxEmailAccount.getUserName() + "解析到内容为空！" + fromaddr + " ，发送时间：" + DateUtil.dateToStr(msg.getSentDate()));
//                                    }
//                                }
//                            }

                            getMailContent(bodyPart,content);

                        }
                    }
//                    getMailTextContent(msg, content);
//                    log.info("===解析到当前邮件的内容是：======》"+content);
                    // 定义正则表达式匹配 HTML 标签
                    String pattern = "(<[^>]*>|&nbsp;|\\s+)";
                    // 创建 Pattern 对象
                    Pattern p = Pattern.compile(pattern);
                    // 创建 Matcher 对象
                    Matcher m = p.matcher(content);
                    // 使用 Matcher 对象替换所有 HTML 标签
                    String stringContent = m.replaceAll("");
                    if(!isMatching(stringContent,from)){
                        continue;
                    }
                    String key = yxEmailAccount.getUserName() + ":" + from + "-" + msg.getSentDate().getTime();
                    String s = redisService.get(key);
                    //同一条邮件异常只通知2次
                    if (StringUtils.isEmpty(s) || Integer.valueOf(s) <= 1) {
                        //当前次数
                        Integer num = StringUtils.isEmpty(s) ? 0 : Integer.valueOf(s);
                        StringBuffer text = new StringBuffer("【" + yxEmailAccount.getAssociatedAccount() + "】触发报警第(" + (num+1) + ")次：<at user_id=\"all\">所有人</at>\n");
                        text.append("\t邮件主题：" + msg.getSubject() + "\n");
                        text.append("\t邮件发送日期：" + DateUtil.dateToStr(msg.getSentDate()) + "\n");
                        text.append("\t发件人：" + fromaddr + "\n");
                        text.append("\t---------------正文---------------\n");
                        text.append("\t" + stringContent);
//                        log.info(text.toString());
                        FeiShuUtil.sendMsgForEmail(text.toString());
                        redisService.increment(key, 1);
                        redisService.expire(key, 24*10 * 60 * 60);
                    }
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                    String dateString = dateFormat.format(new Date());
                    log.info("------------------解析"+dateString+"日收到的邮箱结束，当前是："+fromaddr+"-------------------- ");
                }
            } catch (Exception e) {
                log.error("邮箱" + yxEmailAccount.getUserName() + "监控异常：{}", e);
                FeiShuUtil.sendMsg("邮箱" + yxEmailAccount.getUserName() + "监控异常：" + e.getMessage());
            }finally {
                // 关闭收件箱和Store连接
                if (folder != null && folder.isOpen()) {
                    try {
                        folder.close(false);
                    } catch (MessagingException e) {
                        log.error("folder.close(false)，关闭出错！");
                    }
                }
                if (store != null && store.isConnected()) {
                    try {
                        store.close();
                    } catch (MessagingException e) {
                        log.error("store.close()，关闭出错！");
                    }
                }

            }
        }

    }

    /**
     * 匹配发件人
     * true 存在或者不过滤，false 不存在
     */
    public boolean matchingFrom(String from) {
        List<String> baseContent = new ArrayList<>();
        //todo 定义正则表达式
//        baseContent.add("alipay@mail.alipay.com");
//        baseContent.add("190362531@qq.com");
        if(CollectionUtils.isEmpty(baseContent)){
            return true;
        }else {
            return baseContent.contains(from);
        }
    }

    /**
     * 正则匹配文字
     * @param content 需要匹配的文本
     * @param from 发件人
     * @return boolean true 已匹配到，false 未匹配到
     */
    public boolean isMatching(String content,String from) {
        boolean result = false;
        if(StringUtils.isEmpty(content)){
            return result;
        }
        //正则匹配
        for (String regex : warningWords) {
            Matcher matcher = Pattern.compile(regex).matcher(content);
            while (matcher.find()){
                result = true;
                break;
            }
        }
        //命中关键词，或者发件人命中
        if(result || Arrays.asList("alipay@mail.alipay.com").contains(from)){
            result = true;
        }
        return result;
    }


    /**
     * 解析邮件，把得到的邮件内容保存到一个StringBuffer对象中，解析邮件
     * 主要是根据MimeType类型的不同执行不同的操作，一步一步的解析
     *
     * @param part
     * @throws Exception
     */
    public void getMailContent(Part part, StringBuffer bodyText) throws Exception {
        String contentType = part.getContentType();
        //获得邮件的MimeType类型
        int nameIndex = contentType.indexOf("name");
        boolean conName = false;
        if (nameIndex != -1) {
            conName = true;
        }
        log.info("邮件内容的类型:　" + contentType);
        if (part.isMimeType("text/plain") && conName == false) {
            //text/plain类型
            bodyText.append((String) part.getContent());
        } else if (part.isMimeType("text/html") && conName == false) {
            //text/html类型
            bodyText.append((String) part.getContent());
        } else if (part.isMimeType("multipart/*")) {
            //multipart/*
            Multipart multipart = (Multipart) part.getContent();
            int counts = multipart.getCount();
            for (int i = 0; i < counts; i++) {
                getMailContent(multipart.getBodyPart(i),bodyText);
            }
        } else if (part.isMimeType("message/rfc822")) {
            //message/rfc822
            getMailContent((Part) part.getContent(),bodyText);
        } else {
            log.info("无法解析====》");
        }
    }


    /**
     * 设置邮件参数
     */
    private MimeMessage getMimeMessage(String toEmail, String ccEmail, String bccEmail, String subject, String text,
                                       JavaMailSenderImpl javaMailSender, List<File> files,String senderName) throws javax.mail.MessagingException {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
        //设置邮件的发件人
        mimeMessageHelper.setFrom(senderName);
        //设置邮件的收件人
        mimeMessageHelper.setTo(toEmail.split(","));
        if (!Strings.isNullOrEmpty(ccEmail)) {
            //用于设置邮件的抄送（CC）收件人
            mimeMessageHelper.setCc(ccEmail.split(","));
        }
        if (!Strings.isNullOrEmpty(bccEmail)) {
            //设置邮件的密送（BCC）收件人
            mimeMessageHelper.setBcc(bccEmail.split(","));
        }
        //设置邮件主题
        mimeMessageHelper.setSubject(subject);
        //设置邮件的文本内容。第一个参数 text 是邮件的文本内容，第二个参数 isHtml 表示是否是HTML格式的文本。
        mimeMessageHelper.setText(text, true);
        try {
            if (!CollectionUtils.isEmpty(files)) {
                for (File file : files) {
                    //添加附件。fileName 是附件的文件名，file 是附件的数据源。
                    mimeMessageHelper.addAttachment(MimeUtility.encodeText(file.getName(), "GBK", "B"), file);
                }
            }
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return mimeMessage;
    }

    /**
     * 判断邮件中是否包含附件
     * @return 邮件中存在附件返回true，不存在返回false
     */
    public static boolean isContainAttachment(Part part) throws MessagingException, IOException {
        boolean flag = false;
        if (part.isMimeType("multipart/*")) {
            MimeMultipart multipart = (MimeMultipart) part.getContent();
            int partCount = multipart.getCount();
            for (int i = 0; i < partCount; i++) {
                BodyPart bodyPart = multipart.getBodyPart(i);
                String disp = bodyPart.getDisposition();
                if (disp != null && (disp.equalsIgnoreCase(Part.ATTACHMENT) || disp.equalsIgnoreCase(Part.INLINE))) {
                    flag = true;
                } else if (bodyPart.isMimeType("multipart/*")) {
                    flag = isContainAttachment(bodyPart);
                } else {
                    String contentType = bodyPart.getContentType();
                    if (contentType.indexOf("application") != -1) {
                        flag = true;
                    }

                    if (contentType.indexOf("name") != -1) {
                        flag = true;
                    }
                }

                if (flag) {
                    break;
                }
            }
        } else if (part.isMimeType("message/rfc822")) {
            flag = isContainAttachment((Part) part.getContent());
        }
        return flag;
    }

    /**
     * 设置属性
     * type 1-发送邮件，2-接收邮件
     */
    public Properties getProperties(String platform,Integer type){
        Properties props = new Properties();
        if("163".equals(platform)){
            if(type == 2){
                props.put(IMAP_HOST_KEY, "imap.163.com");
                props.put(IMAP_PORT_KEY, "993");
                props.put(IMAP_AUTH_KEY, true);
                props.put(IMAP_SSL_KEY, true);
                props.put(IMAP_PROTOCOL_KEY, "imap");
            }else if(type == 1){
                props.put(SMTP_HOST_KEY, "smtp.163.com");
                props.put(SMTP_PORT_KEY, "25");
            }else {
                props = null;
            }
        }else if("aliyun".equals(platform)) {
            if(type == 2){
                props.put(IMAP_HOST_KEY, "imap.aliyun.com");
                props.put(IMAP_PORT_KEY, "993");
                props.put(IMAP_AUTH_KEY, true);
                props.put(IMAP_SSL_KEY, true);
                props.put(IMAP_PROTOCOL_KEY, "imap");
            }else if(type == 1){
                props.put(SMTP_HOST_KEY, "smtp.aliyun.com");
                props.put(SMTP_PORT_KEY, "25");
            }else {
                props = null;
            }
        }else {
            props = null;
        }
        return props;
    }
}
